/**
 * Copyright (c) 2009 Cerner Corporation.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Cerner Corporation - initial API and implementation
 */
package com.cerner.system.rest.resource.organizer;

import java.net.URI;
import java.util.Collection;

import com.cerner.system.rest.internal.arguments.BaseUriValidator;
import com.cerner.system.rest.internal.arguments.NotNullValidator;
import com.cerner.system.rest.internal.arguments.Verifier;
import com.cerner.system.rest.resource.organizer.spi.NotThreadSafe;
import com.cerner.system.rest.resource.organizer.spi.ResourceKey;

/**
 * Implementation of the {@link ResourceOrganizer} API that stores resource
 * representations in a {@link java.util.Map} data structure.
 * 
 * @author Alex Horn
 * @param <E> class type of objects that should be cached
 */
@NotThreadSafe
public class MapResourceOrganizer<E> implements ResourceOrganizer<E> {

  /**
   * URIs which is used to {@link java.net.URI#resolve(java.net.URI) resolve}
   * resource URIs must not be {@code null} and it must conform to the absolute
   * URI syntax.
   * 
   * @see BaseUriValidator
   * @see NotNullValidator
   */
  private final static Verifier BASE_URI_VERIFIER;

  static {
    BASE_URI_VERIFIER = new Verifier(new NotNullValidator(),
        new BaseUriValidator());
  }

  /**
   * Internal map data structure used to store, organize and access cached
   * objects.
   */
  private final java.util.Map<ResourceKey, MapResourceRef<E>> map;

  /**
   * @see #BASE_URI_VERIFIER
   */
  private final java.net.URI baseURI;

  /**
   * Instantiate a {@link ResourceOrganizer} object that stores resources in a
   * {@link java.util.Map} data structure. Note that it is not thread-safe.
   * <p>
   * The base URI is used to {@link #resource(java.net.URI) resolve} resource
   * URIs.
   * 
   * @param baseURI base URI must conform to the <a
   *          href="http://tools.ietf.org/html/rfc3986#section-4.3"
   *          >&lt;absolute-URI&gt; syntax rule</a>
   * @throws IllegalArgumentException if the base URI is {@code null} or it does
   *           not conform to the <a
   *           href="http://tools.ietf.org/html/rfc3986#section-4.3"
   *           >&lt;absolute-URI&gt; syntax rule</a>
   */
  public MapResourceOrganizer(final java.net.URI baseURI) {
    checkBaseURI(baseURI);

    this.map = new java.util.HashMap<ResourceKey, MapResourceRef<E>>();
    this.baseURI = baseURI;
  }

  public URI baseURI() {
    return this.baseURI;
  }

  public void clear() {
    this.map.clear();
  }

  public MapResourceController<E> resource(final java.net.URI uri) {
    return new MapResourceController<E>(new ResourceKey(baseURI(), uri), this);
  }

  /**
   * Internal API to place a {@link MapResourceRef} in the underlying map data
   * structure.
   * 
   * @param key key that uniquely identifies a resource in the map
   * @param node resource tree node to be stored in map
   */
  void put(final ResourceKey key, final MapResourceRef<E> node) {
    this.map.put(key, node);
  }

  /**
   * Internal API to remove all {@link MapResourceRef} objects from the cache
   * that match the provided keys.
   * 
   * @param keys set of keys that identify resources to be removed from the map
   */
  void removeAll(final Collection<ResourceKey> keys) {
    for (ResourceKey key : keys) {
      this.map.remove(key);
    }
  }

  /**
   * Internal API to retrieve a particular {@link MapResourceRef} object that is
   * stored in the map.
   * 
   * @param key key that uniquely identifies the resources that should be
   *          retrieved
   * @return node that represents the state of a resource in the tree data
   *         structure
   */
  MapResourceRef<E> get(final ResourceKey key) {
    return this.map.get(key);
  }

  /**
   * Throws an {@link IllegalArgumentException} if the provided URI is {@code
   * null} or it does not conform to the <a
   * href="http://tools.ietf.org/html/rfc3986#section-4.3">&lt;absolute-URI&gt;
   * syntax rule</a>.
   * 
   * @param uri URI to check against {@code null} and &lt;absolute-URI&gt;
   *          syntax rule
   */
  private static void checkBaseURI(final java.net.URI uri) {
    BASE_URI_VERIFIER.names("uri").values(uri);
  }
}
